<template>
    <div class="scoket">
        <a-form
            name="userForm"
            ref="formRef"
            :rules="formRules"
            :model="userForm"
            :labelCol="{ span: 2 }"
        >
            <a-form-item prop="name" label="姓名">
                <a-input v-model:value="userForm.name" :disabled="logined" />
            </a-form-item>
            <a-form-item prop="role" label="角色">
                <a-select
                    v-model:value="userForm.role"
                    placeholder="请选择角色"
                >
                    <a-select-option
                        v-for="item in roleList"
                        :key="item.id"
                        :value="item.role"
                        >{{ item.label }}</a-select-option
                    >
                </a-select>
            </a-form-item>
            <a-form-item>
                <a-button
                    :disabled="logined"
                    type="primary"
                    @click="handleLogin"
                    >登录</a-button
                >
                <a-button
                    :disabled="!logined"
                    type="primary"
                    @click="handleLogout"
                    >登出</a-button
                >
            </a-form-item>
        </a-form>
        <div class="scoket-box">
            <div
                v-for="item in info"
                :key="item.id"
                class="scoket-box-line"
                :style="{
                    justifyContent:
                        item.user === userForm.name
                            ? 'flex-end'
                            : item.isLoginInfo
                            ? 'center'
                            : 'flex-start',
                }"
            >
                <span v-if="item.isLoginInfo" class="sbl-login">{{
                    item.user + item.msg
                }}</span>
                <template v-else>
                    <span
                        class="sbl-user"
                        :style="{
                            order: item.user === userForm.name ? '2' : '1',
                        }"
                    >
                        {{ item.user }}
                    </span>
                    <div
                        class="sbl.msg"
                        :style="{
                            order: item.user === userForm.name ? '1' : '2',
                        }"
                    >
                        {{ item.msg }}
                    </div>
                </template>
            </div>
        </div>
        <hr />
        <a-input-search v-model:value="sendInfo" @keyup.enter="handleSend">
            <template #enterButton>
                <a-button @click="handleSend">发送</a-button>
            </template>
        </a-input-search>
    </div>
</template>
<script setup lang="ts">
import { message } from 'ant-design-vue'
import { onBeforeUnmount, reactive, ref, shallowRef } from 'vue'

// 用户表单
const userForm = ref({
    name: '',
    role: '',
})
const logined = ref(false) // 是否已经登录
const formRef = ref() // 登录表单 dom 对象
// 表单验证规则对象
const formRules = reactive({
    name: { trigger: 'blur', required: true, message: '请输入姓名' },
})
// 角色列表
const roleList = shallowRef([
    { id: '1', label: '学生', role: 'student' },
    { id: '2', label: '老师', role: 'teacher' },
    { id: '3', label: '管理员', role: 'admin' },
])
// 封装 websocket 发送方法
const send = (data: any, type: string = 'info') => {
    if (!formRef.value) return
    formRef.value.validate(Object.keys(userForm.value)).then(() => {
        client.send(JSON.stringify({ type, data, user: userForm.value.name }))
    })
}
// 使用 websocke 登录
const handleLogin = () => {
    send(userForm.value, 'login')
}
const handleLogout = () => {
    send('', 'logout')
}
// 消息列表
const info = ref<
    Array<{ user: string; msg: string; id: string; isLoginInfo?: boolean }>
>([])
// 发送的信息
const sendInfo = ref('')
// 获取 websocket 对象
const client = new WebSocket('ws://127.0.0.1:8080')
// 监听 ws 开启
client.onopen = (res) => {
    // client.setRequestHeader('name', '张三')
    console.log('onopen', res)
}
// 监听 ws 关闭
client.onclose = (res) => {
    console.log('onclose', res)
}
// 监听 ws 信息
client.onmessage = (event) => {
    const data = JSON.parse(event.data)
    console.log('onmessage', event, data)
    switch (data.type) {
        case 'login':
            if (data.code === 'success') logined.value = true
            else {
                message.error(data.msg || '登录失败请重试')
            }
            break
        case 'send':
            if (data.code === 'success') {
                info.value.push(data.data)
                sendInfo.value = ''
            } else {
                message.error('发送失败')
            }
            break
        case 'logout':
            if (data.code === 'success') logined.value = false
            break
        default:
            info.value.push(data.data)
            break
    }
}
client.onerror = (error) => {
    console.log(error)
}
const handleSend = () => {
    send(sendInfo.value)
}
window.addEventListener(
    'close',
    () => {
        client.send(
            JSON.stringify({ type: 'logout', user: userForm.value.name })
        )
        client.close()
    },
    { once: true }
)
onBeforeUnmount(() => {
    client.send(JSON.stringify({ type: 'logout', user: userForm.value.name }))
    client.close()
})
</script>
<style lang="scss" scoped>
.scoket {
    .scoket-box {
        height: 40vh;
        overflow-y: auto;
        .scoket-box-line {
            display: flex;
            &:not(:nth-of-type(1)) {
                margin-top: 10px;
            }
            .sbl-login {
                justify-items: center;
            }
            .sbl-user {
                $size: 30px;
                width: $size;
                height: $size;
                margin: 0 10px;
                line-height: $size;
                text-align: center;
                border-radius: $size;
                background-color: rgba(0, 0, 0, 0.2);
                color: black;
                order: 1;
            }
            .sbl-msg {
                width: calc(100% - 200px);
                order: 2;
            }
        }
    }
}
</style>
